Socket WriteUp
Recon/Scanning
Adding to /etc/hosts…
Checking out the site on 80, we can see Text to QR code page…
Intercepting we can see Werkzeug/2.1.2 from the Server Header…
We can download the QReader binary, I used Ghidra to check it out…
After digging a bit, I realized this could probably be a rabbit hole, but then I seen PyInstaller which triggered the remembrance of a tool that could extract the contents of a PyInstaller generated file. You can find that info digging with Ghidra…
lets extract…
We will need uncompyle6 which is a library that translates Python bytecode back into its equivalent Python source code. It was a pain in the arse because I use 3.11 and this lib only works under 3.8! If you are using hArch you can use altinstall
#Extract
tar -xvf ~/path/to/python
#Configure
cd extracted/content && ./configure
#Make
make
#Install alongside
sudo make altinstall
We can easily attain this with a Virtual Environment!
Looking at qreader.py, there is a function that jumps out…
Why does this look interesting? The way the response is dumping the data ‘version’: VERSION, there does not seem to be any sanitation happening. In theory, if we can inject without breaking the response, we might get back something worth something.
We cannot access it directly, header issues… Lets code WebSockets <3
import asyncio
import websockets
import json
async def connect_to_websocket():
= "ws://qreader.htb:5789/ws" #FUZZ
uri
print("WebSocket connection established!")
# Start sending and receiving messages
while True:
async with websockets.connect(uri) as websocket:
= input("Enter a message: ")
message = {"data": message}
data await websocket.send(json.dumps(data))
print("Message sent!")
try:
= await websocket.recv()
response = json.loads(response)
response_data print("Received message:", response_data)
except websockets.exceptions.ConnectionClosedError as e:
print("WebSocket connection closed with error:", e)
break
asyncio.get_event_loop().run_until_complete(connect_to_websocket())
This is a basic script to send and recv from a WebSocket.
Now with a few mods, we can play around with the /version endpoint…
hmmm.. I wonder if this is vulnerable to SQLi
After a bit of testing and error handling… It is starting too look like it…
Kerpow!
Gaining Access
So we are dealing with a SQL Injection UNION Attack, lets dump something…
MD5?
Cracking…
Crackstation was the quicker option here… but I can’t do anything with this because I have no username. I probably could throw a list of users in Hydra but that is no fun! Back to enumeration…
It took a HOT minute, but finally got something! Lets recap…
We can see a few usernames, I tried Mike, then json (which I thought maybe typo so Jason) all with no success. My AD name creation mind took over and I took Thomas Keller and whipped up a file with a few usernames that could possibly work.
You can quickly test SSH access against a list in your terminal ;)
We made it, and got the user flag…
Privilege Escalation
As always, lets get a feel of where we are and what we can do…
Investigating this build-installer shell file…
/usr/local/sbin/build-installer.sh
#!/bin/bash
if [ $# -ne 2 ] && [[ $1 != 'cleanup' ]]; then
/usr/bin/echo "No enough arguments supplied"
exit 1;
fi
action=$1
name=$2
ext=$(/usr/bin/echo $2 |/usr/bin/awk -F'.' '{ print $(NF) }')
if [[ -L $name ]];then
/usr/bin/echo 'Symlinks are not allowed'
exit 1;
fi
if [[ $action == 'build' ]]; then
if [[ $ext == 'spec' ]] ; then
/usr/bin/rm -r /opt/shared/build /opt/shared/dist 2>/dev/null
/home/svc/.local/bin/pyinstaller $name
/usr/bin/mv ./dist ./build /opt/shared
else
echo "Invalid file format"
exit 1;
fi
elif [[ $action == 'make' ]]; then
if [[ $ext == 'py' ]] ; then
/usr/bin/rm -r /opt/shared/build /opt/shared/dist 2>/dev/null
/root/.local/bin/pyinstaller -F --name "qreader" $name --specpath /tmp
/usr/bin/mv ./dist ./build /opt/shared
else
echo "Invalid file format"
exit 1;
fi
elif [[ $action == 'cleanup' ]]; then
/usr/bin/rm -r ./build ./dist 2>/dev/null
/usr/bin/rm -r /opt/shared/build /opt/shared/dist 2>/dev/null
/usr/bin/rm /tmp/qreader* 2>/dev/null
else
/usr/bin/echo 'Invalid action'
exit 1;
fi
Interesting… we might be able to work with this
If the ‘action’ is ‘build’, it checks if the file extension is ‘spec’. If it is, it removes the directories ‘/opt/shared/build’ and ‘/opt/shared/dist’ if they exist, and then uses the ‘pyinstaller’ command to build the specified file. Finally, it moves the generated ‘dist’ and ‘build’ directories to ‘/opt/shared’
What would happen if we created a malicous .spec file ?
Now we need to build this…
Wrapping Up
“Socket” from Hackthebox presents a thrilling and challenging experience, showcasing the intricacies of a Medium level machine. The utilization of websockets adds an interesting layer of complexity, prompting concerns about potential vulnerabilities if not implemented securely. Engaging in ethical hacking practices, such as WebSocket testing, proves invaluable in uncovering weaknesses in data transmission and authentication mechanisms, ultimately fortifying the overall security of the system.
Moreover, the discovery of a vulnerability in the binary file emphasizes the criticality of adhering to secure software development practices. Ethical hackers play a crucial role in this process, employing various techniques such as binary analysis, code review, and fuzz testing to proactively identify and address vulnerabilities early on in the development lifecycle.
By immersing ourselves in challenges like “Socket,” we not only hone our technical skills but also deepen our understanding of the significance of cybersecurity and the imperative to foster a security-first mindset in all our endeavors. As we continue on our ethical hacking journey, each encounter enriches our expertise and resilience in the ever-evolving landscape of cybersecurity. Together, we strive towards a more secure and resilient digital world.
Amazing challenge by Kavigihan!